home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 8
/
QRZ Ham Radio Callsign Database - Volume 8.iso
/
pc
/
files
/
t_sys5
/
unixkit.tgz
/
unixkit.tar
/
unixkit
/
thread
/
bsdunix.c
next >
Wrap
C/C++ Source or Header
|
1991-12-18
|
21KB
|
913 lines
/* NOS porting kit for 4.3 BSD UNIX
* 890407
*
* Updated by KA9WSB Nov 91
*
* The following text is the original text and does not reflect the
* current changes/environment for NOS and the porting kit. Refer to
* the README file for the current descriptions and documentation. KA9WSB
*
* ----------------------------------------------------------------------
*
* Files are: bsdunix.c, asy.h, bsdksubr.c, bsd_io.c, bsd_nit.c, bsd_tun.c,
* Makefile.bsd
*
* This runs on a SUN-3 and on a NeXT, I have not tested it elsewhere.
* Do not forget to change the definition of JB_SP in bsdksubr.c as required.
*
* The NIT and TUN drivers are activated by defining PACKET in config.h but
* you need to run NOS as root to use them. TUN is the more efficient, so
* I recommend its usage over NIT.
*
* You need release 891022 or later of KA9Q NOS to use these files.
*
* You should insert a "stksize += 2000;" or so in newproc() in kernel.c,
* since more stack space is needed on 32 bit machines. Also change the
* stack assignment to use int's instead of int16's, if you have a 32 bit CPU.
*
* You will probably like to increase the definition of MSPTICK in timer.c
* somewhat, such as doubling it.
*
* Delete any lines in hardware.h that causes compiler errors. You may
* run into other compiler errors as well, caused by differences between
* Turbo-C and UNIX compilers, but they should not be too hard to fix.
*
* You need to modify global.h somewhat. This is how I have done:
*
typedef int int32;
typedef unsigned short int16;
- - -
#define callocw(x,y) calloc(x,y)
#define mallocw(x) malloc(x)
#define availmem() (long)Memthresh
#define ptol(p) (long)p
#define ltop(p) (p)
#ifdef tolower(c)
#undef tolower(c)
#endif
#ifdef UNIX
extern int (*xxfree)();
#define free(p) ((char *)p != NULLCHAR ? (*xxfree)(p) : 0)
extern char *sys_errlist[];
extern int errno;
#endif
char *malloc();
*
* The above definition is needed when one doesn't use alloc.c. The BSD
* free() doesn't check if the argument is a pointer to NULL.
* It seems to be ok not to use alloc.c as long as no calls to malloc()
* etc are done at interrupt level.
*
* Written by Anders Klemets, SM0RGV, klemets@sics.se
* (a few functions at the end were written by Mikel Matthews, N9DVG
* Jere Sandidge, K4FUM, and some others.)
* I would appreciate to see any improvements you make.
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <dirent.h>
#include <ctype.h>
/* KA9WSB
* free handling...
* This is grungy 'cause free() in most unix machines pukes if handed
* a null pointer. So we have to check. The "easy" way is to define
* a variable named "xxfree" which is an indirect pointer to the real
* system free(). Then, in "global.h", we define free to be a macro:
* ((char *)p != NULLCHAR ? (*xxfree)(p) : 0)
* Neat huh??
* Only one problem -- code like this:
* free(*argv++);
* fails! Why? Well, it translates to:
* ((char *)*argv++ != NULLCHAR ? (*xxfree)(*argv++) : 0)
* which increments argv twice; the first time by one byte,
* the second time by whatever argv is declared to be! (this
* little gem was gleaned from kernel.c; it ended up incrementing
* argv by 5 bytes instead of 4) To solve this problem, you are
* offered two choices: search for all every occurence of "free"
* in all the c sources (grep works nicely), and verify that none
* will break if expanded into the above macro. Or, add the
* following flag to the CCFLAGS line in the makefile:
* -DBULLET_PROOF_FREE
*
*/
int free(); /* This must be before we include global.h */
#ifndef BULLET_PROOF_FREE
int (*xxfree)() = free; /* if we are not using alloc.c */
#else
int xyfree(q) char *q;{if(q)return free(q);else return 0;}
#endif
#include "global.h"
#include "config.h"
#include "iface.h"
#include "proc.h"
#include "timer.h"
#include "session.h"
#include "asy.h"
#include "hardware.h"
static void timerint(),inpint();
void iostop();
int32 Clock, StartSec, StartUsec;
int Tick, console;
FILE *Rawterm = stdout;
struct sgttyb mysavetty, savecon;
int console_saved = 0;
int WDTick, WDCurr;
#ifndef NO_INTSTK
int16 Intstk[INTSTK_SIZE]; /* The signal stack */
#endif
/* Interface list header */
struct iface *Ifaces;
/* Keyboard input buffer */
struct fifo Keyboard;
extern struct proc *Display;
int shell=0,intoff=0,inputpending=0,ownpid;
/* KA9WSB
* define MALLOCDEBUG in the makefile to use the malloc debugging stuff.
* Note that if you do this, you will have to load /usr/lib/debug/malloc.o
* before libc in the makefile...
* This is probably a VERY good thing to do, given NOS' tendency to abuse
* memory :-)
*/
#ifdef MALLOCDEBUG
int malloc_debug(); /* in the /usr/lib/debug/malloc.o library */
int malloc_verify(); /* in the /usr/lib/debug/malloc.o library */
#endif
/* KA9WSB
* Debugging trick... #define QUERY_INPUT and NOS will check the NOS_TTY
* environment variable for the device to use for input... thus making
* it possible to debug NOS under dbxtool. Fire up another shelltool,
* use the tty command to find out the tty name (something like
* /dev/ttyp2), and then type "sleep 30000" to make the shell in that
* window go away. Now in another shelltool type "setenv NOS_TTY
* /dev/ttyp2", fire up dbxtool with nos in it, type "ignore IO"
* (so dbxtool will let nos handle the SIGIO envents, and type "run".
* NOS will now be happily taking input from the sleeping window.
*/
#define QUERY_INPUT
/* Called at startup time to set up console I/O, memory heap */
void
ioinit()
{
struct sgttyb ttybuf;
struct timeval tp;
char *ttydev;
#ifndef NO_INTSTK
struct sigstack ss;
struct sigvec sv;
#endif
#ifdef MALLOCDEBUG
#ifndef MALLOCDEBUG_LEVEL
#define MALLOCDEBUG_LEVEL 2
#endif
(void)malloc_debug(MALLOCDEBUG_LEVEL);
#endif
/* begin by recording the start time as NOW */
gettimeofday(&tp,NULL);
StartSec = tp.tv_sec;
StartUsec = tp.tv_usec;
Clock = 0;
/* We want unbuffered output */
if(isatty(1)) {
#ifndef BUFFERED_OUTPUT
freopen(ttyname(1),"w",stdout);
setbuf(stdout,NULLCHAR);
#endif
#ifdef QUERY_INPUT
ttydev = getenv("NOS_TTY");
if(ttydev==NULL) ttydev = "/dev/tty";
#else
ttydev = "/dev/tty";
#endif
if ((console = open(ttydev,O_RDONLY|O_NDELAY)) < 0) {
perror(ttydev);
exit(1);
}
ioctl(console,TIOCGETP,&ttybuf);
savecon = ttybuf;
ttybuf.sg_flags &= ~ECHO;
ttybuf.sg_flags |= CBREAK;
ioctl(console,TIOCSETP,&ttybuf);
console_saved = 1;
}
else console = 0;
(void) signal(SIGHUP, iostop);
(void) signal(SIGINT, iostop);
(void) signal(SIGQUIT, iostop);
(void) signal(SIGTERM, iostop);
/* Initialize keyboard queue */
Keyboard.bufsize = 256;
Keyboard.buf = malloc (256);
Keyboard.rp = Keyboard.wp = Keyboard.buf;
/* Create the signal stack.
Note that if you don't use one, you may have to make the
process's stacks considerably larger. Watch out for
alignment on the signal stack */
#ifndef NO_INTSTK
ss.ss_sp = (char *)((int)&Intstk[(INTSTK_SIZE-1)] & 0xfffffff8);
ss.ss_onstack = 0;
sigstack (&ss, (struct sigstack *)0);
/* Set up interrupts. If your system doesn't support sigvec(),
you may skip the signal stack stuff and use signal() instead. */
sv.sv_flags = SV_ONSTACK; /* We want to execute on the signal stack */
sv.sv_handler = timerint;
sv.sv_mask = sigmask(SIGALRM);
sigvec(SIGALRM,&sv,(struct sigvec *)0);
sv.sv_handler = inpint;
sv.sv_mask = sigmask(SIGIO);
sigvec(SIGIO,&sv,(struct sigvec *)0);
#else
signal(SIGALRM,timerint);
signal(SIGIO, inpint);
#endif
/* Get the process ID of this program, we might want to kill
ourselves later. */
ownpid = getpid();
/* This will send a SIGIO signal whenever a key is pressed and
the stdin queue is empty. It would be better if the signal would
always be sent, regardless of the status of the queue. */
if(isatty(console)) {
fcntl(console,F_SETFL, fcntl(console,F_GETFL,0) | FASYNC);
fcntl(console,F_SETOWN,ownpid);
}
/* We will get a SIGALRM signal at every MSPTICK milliseconds.
You may try to tweak its definiton in timer.h */
ualarm (100000,MSPTICK*1000);
}
void
ctick(p, v1, v2) /* satisfy reference... */
int p;
void *v1, *v2;
{
}
/* Called just before exiting to restore console state */
void
iostop()
{
struct iface *ifp, *ifptmp;
void (**fp)();
for(ifp = Ifaces; ifp != NULLIF; ifp = ifptmp){
ifptmp = ifp->next;
if_detach(ifp);
}
for(fp = Shutdown; *fp != NULLVFP; fp++){
(**fp)();
}
if(console_saved)
ioctl(console,TIOCSETP,&savecon);
exit(0);
}
/* Disable all "interrupts", don't mask any signals however */
int dirps()
{
int mask;
if (intoff)
return 0;
intoff = 1;
return 1;
}
/* Restore the "interrupts" */
void restore (mask)
char mask;
{
if (mask) {
intoff = 0;
/* If we got a SIGIO when the interrupts where disabled, take care
of it now, by reissueing it. */
if (inputpending)
kill (ownpid, SIGIO); /* Argh */
}
}
/* Return the interrupt state */
int istate()
{
return !intoff;
}
/* Input interrupt handler.
This function is called whenever there is input from stdin, the
asynchronus interfaces or the NIT driver. But unfortunately only if their
respective input queues were empty.
Speeding up this function would probably enhance the general performance
of the program.
*/
static void
inpint()
{
int i,ok,r,turn,cnt;
char i_state;
struct timeval timeout;
fd_set readfds;
if (intoff) {
/* Interrupts are off, the input will be taken care of later */
inputpending = 1;
return;
}
inputpending = 0;
i_state = dirps(); /* turn off interrupts */
signal(SIGIO,inpint); /* and reenable signals */
/* We use select() to se which file descriptors are ready for reading.
The syntax of select() differs between 4.2 and 4.3 BSD.
*/
timeout.tv_sec = 0;
timeout.tv_usec = 35;
FD_ZERO (&readfds);
/* This loop exits first when there is nothing to ready from the
asynchronus interfaces. */
for (turn=0;;++turn) {
for (i=0; i<Nasy; ++i)
FD_SET(Asy[i].IORser,&readfds);
#ifdef PACKET
/* This is only for the NIT and Tun drivers */
for (i=0; i<Nnit; ++i)
FD_SET(Nitdrvr[i].IOser,&readfds);
for (i=0; i<Ntun; ++i)
FD_SET(Tundrvr[i].IOser,&readfds);
#endif
if(isatty(console))
FD_SET(console,&readfds);
ok = select(NOFILE,&readfds,(fd_set *)0,(fd_set *)0,&timeout);
cnt = 0;
if (ok > 0) {
#ifdef PACKET
for (i=0; i<Nnit; ++i)
if (FD_ISSET(Nitdrvr[i].IOser,&readfds) && !turn)
psignal(&Nitdrvr[i],1);
for (i=0; i<Ntun; ++i)
if (FD_ISSET(Tundrvr[i].IOser,&readfds) && !turn)
psignal(&Tundrvr[i],1);
#endif
/* Now scan the asynchronus interfaces. Remember, this is
supposed to be efficient. */
for (i=0; i<Nasy; ++i)
if (FD_ISSET(Asy[i].IORser,&readfds)) {
if (Asy[i].fifo.cnt == Asy[i].fifo.bufsize)
continue; /* No room */
/* Try to read as much as we are allowed to */
r = read(Asy[i].IORser, Asy[i].fifo.wp,
Asy[i].fifo.rp > Asy[i].fifo.wp ?
Asy[i].fifo.rp - Asy[i].fifo.wp :
&Asy[i].fifo.buf[Asy[i].fifo.bufsize] - Asy[i].fifo.wp);
if (r <= 0)
continue;
cnt += r;
Asy[i].rxchar += r;
Asy[i].fifo.wp += r;
Asy[i].fifo.cnt += r;
if(Asy[i].fifo.wp >= &Asy[i].fifo.buf[Asy[i].fifo.bufsize])
/* Wrap around */
Asy[i].fifo.wp = Asy[i].fifo.buf;
/* Signal "asy_rx" that we have got new data. */
psignal(&Asy[i].fifo,1);
}
}
if (turn && cnt == 0){ /* To prevent endless loops */
restore(i_state);
return;
}
/* This function would be a monster if I didn't split it up
into a special part for keyboard input. */
if (ok > 0 && FD_ISSET(console,&readfds))
kbraw();
/* Now do it all over again since we might have received more input */
}
}
/* Read characters from stdin. Called from the generic interrupt handler. */
int
kbraw()
{
int cnt;
if (shell)
/* We are executing a shell right now */
return 0;
if (Keyboard.cnt == Keyboard.bufsize)
return 0;
/* Try to read as much as we are allowed to */
cnt = read(console, Keyboard.wp,
Keyboard.rp > Keyboard.wp ? Keyboard.rp - Keyboard.wp :
Keyboard.buf + Keyboard.bufsize - Keyboard.wp);
if (cnt <= 0)
return 0;
Keyboard.cnt += cnt;
Keyboard.wp += cnt;
if(Keyboard.wp >= Keyboard.buf + Keyboard.bufsize)
Keyboard.wp = Keyboard.buf;
psignal(&Keyboard,1);
return cnt;
}
/* Blocking read from the keyboard */
int
kbread()
{
int i_state;
char c;
i_state = dirps();
while(Keyboard.cnt == 0)
pwait (&Keyboard);
c = *Keyboard.rp++;
if(Keyboard.rp == &Keyboard.buf[Keyboard.bufsize])
Keyboard.rp = Keyboard.buf;
Keyboard.cnt--;
restore(i_state);
if (c == 0x7f) /* DEL key */
c = '\b';
if (c == '\n') /* Emulate MS/DOS. SysV would reset the ICRNL flag */
c = '\r';
return c;
}
void
systick()
{
}
void
sysreset()
{
}
/* timerint() is called at every clock tick. If interrupts are supposed
to be disabled, we do nothing except increasing Tick to keep the time
accurately. */
static void
timerint() /* ctick() */
{
++Tick;
if (!intoff)
psignal(&Tick,1);
}
/* This function is only needed if you DO use alloc.c */
unsigned long coreleft()
{
struct rlimit rlp;
extern end;
getrlimit(RLIMIT_CORE,&rlp);
return ((unsigned long) (rlp.rlim_cur - end));
}
/* Sleep gracefully until the next interrupt. */
void
giveup()
{
int old;
old = istate();
restore(1); /* Interrupts must be enabled */
sigpause(0);
if(old == 0) /* Interrupts were originally disabled */
dirps();
}
/* To be removed if alloc.c is to be used */
memstat()
{
return 0;
}
/* Note: make sure that there is no previous definition of tolower() */
char tolower (c)
char c;
{
return ((c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c);
}
FILE *
tmpfile()
{
FILE *tmp;
char *mktemp();
char *ptr = "SMTPXXXXXX";
char *name;
name = mktemp(ptr);
if ( ( tmp = fopen(name, "w+") ) == NULL)
{
tprintf("tmpfile: counld not create temp file.\n");
return(NULL);
}
(void) unlink(name);
return ( tmp );
}
/* wildcard filename lookup */
filedir(name, times, ret_str)
char *name;
int times;
char *ret_str;
{
static char dname[128], fname[128];
static DIR *dirp = NULL;
struct dirent *dp;
struct stat sbuf;
char *cp, temp[128];
/*
* Make sure that the NULL is there in case we don't find anything
*/
ret_str[0] = '\0';
if (times == 0) {
/* default a null name to *.* */
if (name == NULL || *name == '\0')
name = "*.*";
/* split path into directory and filename */
if ((cp = strrchr(name, '/')) == NULL) {
strcpy(dname, ".");
strcpy(fname, name);
} else {
strcpy(dname, name);
dname[cp - name] = '\0';
strcpy(fname, cp + 1);
/* root directory */
if (dname[0] == '\0')
strcpy(dname, "/");
/* trailing '/' */
if (fname[0] == '\0')
strcpy(fname, "*.*");
}
/* close directory left over from another call */
if (dirp != NULL)
closedir(dirp);
/* open directory */
if ((dirp = opendir(dname)) == NULL) {
tprintf("Could not open DIR (%s)\n", dname);
return;
}
} else {
/* for people who don't check return values */
if (dirp == NULL)
return;
}
/* scan directory */
while ((dp = readdir(dirp)) != NULL) {
/* test for name match */
/* if (wildmat(dp->d_name, fname)) {*/
if (!strcmp(dp->d_name, fname) || (fname[0] == '*' &&
!strcmp(&dp->d_name[strlen(dp->d_name) - strlen(fname)+1],
&fname[1]))) { /* ...when we do not use wildmat */
/* test for regular file */
sprintf(temp, "%s/%s", dname, dp->d_name);
if (stat(temp, &sbuf) < 0)
continue;
if ((sbuf.st_mode & S_IFREG) == 0)
continue;
strcpy(ret_str, dp->d_name);
break;
}
}
/* close directory if we hit the end */
if (dp == NULL) {
closedir(dirp);
dirp = NULL;
}
}
doshell(argc, argv)
char **argv;
{
register int pid, pid1, i;
void (*savi)();
int rc;
char str[256], *cp;
struct sgttyb ttybuf;
extern struct sgttyb savecon;
shell = 1;
ioctl(console, TIOCGETP, &ttybuf);
ioctl(console, TIOCSETP, &savecon);
str[0] = '\0';
for (i = 1; i < argc; i++) {
strcat(str, argv[i]);
strcat(str, " ");
}
if ((cp = getenv("SHELL")) == NULLCHAR)
cp = "/bin/sh";
if ((pid = fork()) == 0) {
seteuid(getuid()); /* Restore original user ID */
if (argc > 1)
(void)execl(cp, cp, "-c", str, 0);
else
(void)execl(cp, cp, (char *)0,(char *)0,0);
tprintf("Can't execl() (%d)\n", errno);
exit(1);
} else if (pid == -1) {
tprintf("Can't fork() (%d)\n", errno);
rc = -1;
} else {
savi = signal(SIGINT, SIG_IGN);
while ((pid1 = wait(&rc)) != pid && pid1 != -1)
;
signal(SIGINT, savi);
}
ioctl(console, TIOCSETP, &ttybuf);
shell = 0;
return (rc);
}
dodir(argc, argv)
char **argv;
{
register int i;
char str[256];
strcpy(str, "ls -lL ");
for (i = 1; i < argc; i++) {
strcat(str, argv[i]);
strcat(str, " ");
}
return system(str);
}
/* Terminal printf that counts newlines. At end of the page,
* prints "--More--" and waits for a keystroke before continuing.
*/
void
display(i,v1,v2)
int i;
void *v1;
void *v2;
{
int c;
char i_state;
struct session *sp;
/* This is very tricky code. Because the value of "Current" can
* change any time we do a pwait, we have to be careful to detect
* any change and go back and start again.
*/
for(;;){
sp = Current;
if(sp->morewait){
pwait(&sp->row);
if(sp != Current || sp->row <= 0){
/* Current changed value, or the user
* hasn't really hit a key
*/
continue;
}
/* Erase the prompt */
printf("\r \r");
}
sp->morewait = 0;
if((c = recvchar(sp->output)) == -1){
/* the alert() in swapscreen will cause this to
* return -1 when current changes
*/
pwait(NULL); /* Prevent a nasty loop */
continue;
}
fputc(c,stdout);
if(sp->record != NULLFILE){
fputc(c,sp->record);
}
if(sp->flowmode && c == '\n' && --sp->row <= 0){
printf("--More--");
sp->morewait = 1;
}
}
}
void swapscreen(old, new)
struct session *old;
struct session *new;
{
char i_state;
if(old == new)
return; /* Nothing to do */
fflush(stdout);
if(old != NULLSESSION){
/* Save old screen */
}
if(new != NULLSESSION){
/* Load new screen */
}
alert(Display,1); /* Wake him up */
}
void
newscreen(sp)
struct session *sp;
{
if(sp != NULLSESSION)
sp->screen = (struct screen *)callocw(1,sizeof(struct screen));
}
void
freescreen(sp)
struct session *sp;
{
if(sp == NULLSESSION || sp->screen == NULLSCREEN)
return;
if(sp->screen->save != NULLCHAR)
free(sp->screen->save);
free((char *)sp->screen);
}
/* Case-insensitive string comparison (Needed on some machines) */
int
stricmp(a,b)
register char *a,*b;
{
char a1,b1;
while((a1 = *a++) != '\0' && (b1 = *b++) != '\0'){
if(a1 == b1)
continue; /* No need to convert */
if(isupper(a1))
a1 = tolower(a1);
if(isupper(b1))
b1 = tolower(b1);
if(a1 == b1)
continue; /* NOW they match! */
if(a1 > b1)
return 1;
if(a1 < b1)
return -1;
}
return 0;
}
/* Create directory */
int
domkd(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(mkdir(argv[1]) == -1)
tprintf("Can't make %s: %s\n",argv[1],sys_errlist[errno]);
return 0;
}
/* Remove directory */
int
dormd(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(rmdir(argv[1]) == -1)
tprintf("Can't remove %s: %s\n",argv[1],sys_errlist[errno]);
return 0;
}
/* Routines we don't do... but don't want to constantly hack config.c */
int
dofkey(argc,argv,p)
int argc;
char *argv[];
void *p;
{
tprintf("This command is not supported under UNIX yet...\n");
return 0;
}
int
dobmail(argc,argv,p)
int argc;
char *argv[];
void *p;
{
tprintf("This command is not supported under UNIX yet...\n");
return 0;
}
void rflush()
{
char i_state;
fflush(Rawterm);
}
char Hashtab[256];
int16
hash_ip(ipaddr)
int32 ipaddr;
{
return 0; /* A nicer technique later on :-) KA9WSB */
}
void
kbint()
{
}
void
uchtimer()
{
}
int32
secclock()
{
struct timeval tp;
int32 t, u;
gettimeofday(&tp,NULL);
t = tp.tv_sec - StartSec;
u = tp.tv_usec - StartUsec;
if(u>499999)t++;
return t;
}
int32
msclock()
{
struct timeval tp;
int32 t, u;
gettimeofday(&tp,NULL);
t = tp.tv_sec - StartSec;
u = tp.tv_usec - StartUsec;
return ((t * 1000) + (u / 1000));
}
#ifdef BUFFERED_OUTPUT
int FlushTock = 0;
#ifndef TICKS_PER_FLUSH
#define TICKS_PER_FLUSH 5
#endif
#endif
#ifdef MALLOCDEBUG
int MallocTock = 0;
#endif
void
pctick()
{
char i_state;
Clock++;
#ifdef BUFFERED_OUTPUT
FlushTock++;
if(FlushTock>=TICKS_PER_FLUSH){
fflush(stdout);
fflush(stderr);
FlushTock = 0;
}
#endif
#ifdef MALLOCDEBUG
MallocTock++;
if(MallocTock>=10){
i_state = dirps(); /* turn off interrupts */
if( malloc_verify() == 0 )
printf("Warning: malloc_verify: Corrupted heap!\n");
MallocTock = 0;
restore(i_state);
}
#endif
}